package com.weishi.pay.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.weishi.pay.api.constant.RedisCacheConstants;
import com.weishi.pay.api.dto.PaymentDto;
import com.weishi.pay.api.dto.VoPaymentLog;
import com.weishi.pay.api.dto.VoRefundLog;
import com.weishi.pay.api.exception.PayErrors;
import com.weishi.pay.api.service.PaymentLogService;
import com.weishi.pay.api.service.RefundLogService;
import com.weishi.pay.api.service.RocketMqService;
import com.weishi.pay.api.service.WexiPublicService;
import com.weishi.pay.utils.IdUtils;
import com.weishiinfo.commons.vo.H5BaseRequestParameter;
import com.weishiinfo.commons.vo.ResultResponse;
import com.weishiinfo.commons.vo.annotation.LoginRequired;
import com.weishinfo.acenter.vo.VoPayOrderInfo;
import com.weishinfo.order.rpc.api.OrderService;
import com.weishinfo.order.vo.VoOrder;

import io.swagger.annotations.Api;


/**
 * 微信公众号支付
 *
 * @author liufeng
 * @create 2018-07-03 18:37
 **/
@RestController
@RequestMapping(value="/weixinPublic",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Api(value = "/weixinPublic", description = "微信公众号支付")
public class PaymentController   {
    private static final Logger LOGGER = LoggerFactory.getLogger(PaymentController.class);
    @Reference
    WexiPublicService wexiPublicService;
    @Reference
    PaymentLogService paymentLogService;
    @Reference
    RocketMqService rocketMqService;
    @Reference
    RefundLogService refundLogService;
    @Reference
    OrderService payOrderService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;



    /**
     * 前台鉴权后 发起请求 获得预支付id 由h5发起jspi支付请求
     */
    @RequestMapping({"/pay"})
    @ResponseBody
    @LoginRequired
    public ResultResponse pay(H5BaseRequestParameter brp, @RequestBody PaymentDto paymentDto, HttpServletRequest request)  {
//        LOGGER.info("统一下单H5BaseRequestParameter= "+brp.toString()+"==="+paymentDto.getOrderNo());
        LOGGER.info("统一下单H5BaseRequestParameter= "+paymentDto.getOrderNo());
        String orderNo = paymentDto.getOrderNo();
        //调用订单接口
         VoOrder voOrder=payOrderService.findOrderByOrderNo(orderNo);
         if(voOrder ==null){
             throw PayErrors.NULL_ORDER.bornException();
         }
        LOGGER.info("#############voOrder################"+JSONObject.toJSONString(voOrder));
        Integer userId = voOrder.getUserId();
        double amount =voOrder.getOrderAmountTotal()==null?0:voOrder.getOrderAmountTotal();
        //存支付记录表
        VoPaymentLog voPaymentLog = new VoPaymentLog();
        voPaymentLog.setUserId(userId);
        voPaymentLog.setOrderNo(orderNo);
        voPaymentLog.setAmount((int)(amount*100));
        String payNo = IdUtils.next();
        voPaymentLog.setPayNo(payNo);
        paymentLogService.insertLog(voPaymentLog);

        paymentDto.setPayNo(payNo);
        LOGGER.info("统一下单 订单号orderId=" + orderNo + "支付流水号payNo=" + payNo);
        paymentDto.setGetLocalAddr(request.getLocalAddr());
        LOGGER.info("getLocalAddr=" + request.getLocalAddr());
        paymentDto.setUserId(voOrder.getUserId());
        paymentDto.setTotalFee((int) (voOrder.getOrderAmountTotal()*100));
        Map retMap = wexiPublicService.pay(paymentDto);

        //订单对应支付流水号的业务类型  用与区分mq
        redisTemplate.opsForValue().set(RedisCacheConstants.PAY_BUSSINESS_TYPE_PREFIX +payNo,voOrder.getBusinessType());
        return  ResultResponse.ok(retMap);
    }


    /**
     * 支付回调
     */
    @RequestMapping("/afterPay")
    @ResponseBody
    public ModelAndView afterPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
        LOGGER.info("支付回调");
        ModelAndView modelAndView = new ModelAndView();
        String xml = "";
        try {
            xml = IOUtils.toString(request.getInputStream(), "UTF-8");

        } catch (IOException e) {
            e.printStackTrace();
        }
        if (StringUtils.isEmpty(xml)) {
            modelAndView.addObject("message", "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>");
            return modelAndView;
        }

        Map<String, String> requetMap = wexiPublicService.getRequestMap(xml);
        LOGGER.info("回调参数requetMap=" + requetMap);
        String payNo = requetMap.get("out_trade_no");

        //微信超时重复请求处理
        Object objPayNo = redisTemplate.opsForValue().get(RedisCacheConstants.PAY_REPEAT_AFTER_CODE_PREFIX + payNo);
        if(objPayNo != null){
            modelAndView.addObject("message", "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
            return modelAndView;
        }
        redisTemplate.opsForValue().set(RedisCacheConstants.PAY_REPEAT_AFTER_CODE_PREFIX+payNo,"1",24*3600, TimeUnit.SECONDS);


        if (StringUtils.equals(requetMap.get("return_code"), "SUCCESS")) {

            //查询订单
            VoPaymentLog  voPaymentLog =paymentLogService.selectOrderDetail(payNo);
            LOGGER.info("支付流水号payNo="+payNo+"对应订单号orderNo="+voPaymentLog.getOrderNo());


            if (StringUtils.equals(requetMap.get("result_code"), "SUCCESS")) {
                //单位为分
                int amount = Integer.valueOf(requetMap.get("total_fee"));
                int payAmount = paymentLogService.selectPayAmount(payNo);
                //核对订单金额
                if (amount == payAmount) {
                    LOGGER.info("订单金额核对成功 发送mq消息");
                    //发送mq消息
                    doMq(voPaymentLog);

                    //更新支付记录
                    voPaymentLog.setStatus(1);
                    voPaymentLog.setIsMq(1);
                    paymentLogService.updatePayLog(voPaymentLog);
                } else {
                    voPaymentLog.setStatus(2);
                    paymentLogService.updatePayLog(voPaymentLog);
                }

            } else {
                LOGGER.info("##################updatePayLog2");
                voPaymentLog.setStatus(2);
                paymentLogService.updatePayLog(voPaymentLog);
            }
            modelAndView.addObject("message", "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");

        } else {
            modelAndView.addObject("message", "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>");
        }

        return modelAndView;
    }

    @RequestMapping("/refund")
    @ResponseBody
    @LoginRequired
    public ResultResponse refund(@RequestBody VoRefundLog voRefundLog) throws Exception {
        LOGGER.info("pay-controller:paymentController:refund 退款");
        String payNo = voRefundLog.getOrderNo();
        int userId = voRefundLog.getUserId();
        int amount = voRefundLog.getTotalFee();
        //查询支付表记录 并判断是否支付成功
        Map selectMap = new HashMap();
        selectMap.put("payNo", payNo);
        int num = paymentLogService.selectByMap(selectMap);
        if (num != 1) {
            throw PayErrors.REFUND_ERROR.bornException();

        }
        //存退款记录表
        String refundNO = IdUtils.next();
        voRefundLog.setRefundNo(refundNO);
        refundLogService.insertLog(voRefundLog);

        //发起退款请求
        PaymentDto paymentDto = new PaymentDto();
        paymentDto.setPayNo(payNo);
        paymentDto.setUserId(userId);
        paymentDto.setRefundDesc(voRefundLog.getRefundDesc());
        paymentDto.setTotalFee(voRefundLog.getTotalFee());
        paymentDto.setShopId(voRefundLog.getShopId());
        paymentDto.setRefundFee(voRefundLog.getRefundFee());
        paymentDto.setRefundNo(refundNO);
        Map<String,String> flagMap = wexiPublicService.refund(paymentDto);
        return ResultResponse.ok(flagMap);
    }


    /**
     * 退款回调
     */
    @RequestMapping("/afterRefund")
    @ResponseBody
    public ModelAndView afterRefund(HttpServletRequest request, HttpServletResponse response) throws Exception {
        LOGGER.info("退款回调");
        ModelAndView modelAndView = new ModelAndView();
        String xml = "";
        try {
            xml = IOUtils.toString(request.getInputStream(), "UTF-8");
            LOGGER.info("退款回调参数xml=" + xml);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (StringUtils.isEmpty(xml)) {
            modelAndView.addObject("message", "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>");
        }

        Map<String, String> requetMap = wexiPublicService.getRequestMap(xml);

        if (StringUtils.equals(requetMap.get("return_code"), "SUCCESS")) {
            Map updateMap=new HashMap();
            String refundNO=requetMap.get("out_refund_no");

            if (StringUtils.equals(requetMap.get("result_code"), "SUCCESS")) {
                //退款成功
                LOGGER.info(requetMap.get("return_msg"));
                modelAndView.addObject("message", "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                //更新数据
                updateMap.put("status","1");
                updateMap.put("refundDesc",updateMap.get("SUCCESS"));
                updateMap.put("refundNo",refundNO);
                refundLogService.updateStatus(updateMap);

            } else {
                LOGGER.info(requetMap.get("return_msg"));
                modelAndView.addObject("message", "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>");
                updateMap.put("status","2");
                updateMap.put("refundDesc",requetMap.get("return_msg"));
                updateMap.put("refundNo",refundNO);
                refundLogService.updateStatus(updateMap);
            }

        }
        return modelAndView;
    }

    /**
     * 发送mq消息
     * @param voPaymentLog
     */
    public void doMq(VoPaymentLog  voPaymentLog){
        String payNo=voPaymentLog.getPayNo();
        String businessType=(String) redisTemplate.opsForValue().get(RedisCacheConstants.PAY_BUSSINESS_TYPE_PREFIX+payNo);
        //判断业务类型
        if(businessType.equals("S01")){
            //商家入住
            VoPayOrderInfo voPayOrderInfo =new VoPayOrderInfo();
            voPayOrderInfo.setFee((double) voPaymentLog.getAmount()/100);
            voPayOrderInfo.setOrderType(2);
            voPayOrderInfo.setUid((long)voPaymentLog.getUserId());
            voPayOrderInfo.setUtype(2);
            voPayOrderInfo.setOrderId(voPaymentLog.getOrderNo());
            rocketMqService.sendMsg("PayOrder", "Insert", JSONObject.toJSONString(voPayOrderInfo));
        }else if(businessType.equals("S02")){
            //预约订单类型
            VoOrder voOrder=new VoOrder();
            voOrder.setOrderNo(voPaymentLog.getOrderNo());
            voOrder.setOrderTradeNo(payNo);
            rocketMqService.sendMsg("mobilepay","mobileTag",JSONObject.toJSONString(voOrder));

        }else if(businessType.equals("S03")){
            //天使入驻
            VoPayOrderInfo voPayOrderInfo =new VoPayOrderInfo();
            voPayOrderInfo.setFee((double) voPaymentLog.getAmount()/100);
            voPayOrderInfo.setOrderType(2);
            voPayOrderInfo.setUid((long)voPaymentLog.getUserId());
            voPayOrderInfo.setUtype(3);
            voPayOrderInfo.setOrderId(voPaymentLog.getOrderNo());
        }

    }
    /**
     * test
     */
    @RequestMapping("/test")
    @ResponseBody
    public void test(){
        //预约订单类型
        VoOrder voOrder=new VoOrder();
        voOrder.setOrderNo("1111");
        voOrder.setOrderTradeNo("22222");
       // rocketMqService.sendMsg("mobilePay","mobileTag",JSONObject.toJSONString(voOrder));

        rocketMqService.sendMsg("mobilePay","mobileTag",JSONObject.toJSONString(voOrder));
    }

}
